#ifndef CONTROLE_CPP
#define CONTROLE_CPP

#include "fila.cpp"
#include <iostream>
#include "servidor.cpp"
#include "estatistica.cpp"

using namespace std;

class Controle {
private:
	Estatistica estatistica;
	int rodadaAtual;
	int quantIndividuosAtendidosRodada;
	int quantIndividuosGeradosRodada;
	bool fimTransiente;
	int tamRodada;
	bool estouEmRodada;

public:
	Controle()
	{
		rodadaAtual = 0;
		fimTransiente = true;
		estouEmRodada = false;
		quantIndividuosGeradosRodada = 0;
		quantIndividuosAtendidosRodada = 0;
		tamRodada = 200;


	}
	Estatistica& getEstatistica() {
		return estatistica;

	}
	void comecarNovaRodada(double tempoAtual) {
		rodadaAtual++;
		estouEmRodada = true;
		estatistica.setInicioRodada(tempoAtual);
	}

	int getRodadaAtual(){
		return rodadaAtual;
	}

	void terminaRodada(Filas &fila, Servidor &servidor, double tempoAtual) {
		//fila.initSemente();
		//servidor.initSemente();
		estatistica.salvarEstatisticas(tempoAtual);
		estatistica.reset();

		quantIndividuosAtendidosRodada = 0;
		quantIndividuosGeradosRodada = 0;
		estouEmRodada = false;

		comecarNovaRodada(tempoAtual);

	}
	bool fimFaseTransiente() {
		return fimTransiente;
	}

	void setFimFaseTransiente(bool b){
		fimTransiente = b;
	}
	double atualizaSistema(Filas &filas, Servidor &servidor,float const tempoAtual) {

		if (filas.sizeFila1() == 0 && filas.sizeFila2() == 0 && servidor.getStatus() == OCIOSO) { //caso1
			return tratarChegadaFila1(filas, servidor);
		}

		if (filas.sizeFila1() == 0 && servidor.getStatus() == OCUPADO) { //caso2
			if (servidor.getIndividuoAtual().getTipo() == 1) {
				double t1 = checarChegadaFila1(filas);
				double t2 = checarTerminoServico(servidor);
				if (t2 < t1)
					return tratarTerminoServico(filas, servidor);
				else
					return tratarChegadaFila1(filas, servidor);

			} else {
				double t1 = checarChegadaFila1(filas);
				double t2 = checarTerminoServico(servidor);
				if (t2 < t1)
					return tratarTerminoServico(filas, servidor);
				else
					return tratarInterrupcao(filas, servidor, t1);
			}
		}

		if (filas.sizeFila1() == 0 && filas.sizeFila2() > 0	&& servidor.getStatus() == OCIOSO) { //caso3
			return atenderFila2(filas, servidor, tempoAtual);
		}

		if (filas.sizeFila1() > 0 && servidor.getStatus() == OCIOSO) { //caso4
			return atenderFila1(filas, servidor, tempoAtual);
		}

		if (filas.sizeFila1() > 0 && servidor.getStatus() == OCUPADO) { //caso5
			if (servidor.getIndividuoAtual().getTipo() == 1) {
				double t1 = checarChegadaFila1(filas);
				double t2 = checarTerminoServico(servidor);
				if (t2 < t1)
					return tratarTerminoServico(filas, servidor);
				else
					return tratarChegadaFila1(filas, servidor);
			} else {
				return tratarInterrupcao(filas, servidor, tempoAtual);

			}
		}
		cout << "deu M"<<endl;
		return -2.0;
	}

	double checarChegadaFila1(Filas &filas) {
		return filas.getTempoProximaChegadaFila1();
	}

	double checarTerminoServico(Servidor &servidor) {
		if (servidor.getIndividuoAtual().getTipo() == 1) {
			return servidor.getIndividuoAtual().getX1()+ servidor.getIndividuoAtual().getTempoChegadaServidor1();
		} else
		{
			return servidor.getIndividuoAtual().getXr()+ servidor.getIndividuoAtual().getTempoChegadaServidor2();
		}

	}

	double tratarChegadaFila1(Filas &filas, Servidor &servidor) {
		if(estouEmRodada) quantIndividuosGeradosRodada++;

		if (quantIndividuosGeradosRodada <= tamRodada && estouEmRodada)
		{

			filas.geraIndividuos(rodadaAtual);
		}
		else
		{
			filas.geraIndividuos();
		}

		filas.chegadaFila1();

		if(filas.getLastIndividuoFila1().getCor() == rodadaAtual){
			estatistica.setTempoFimEvento1(filas.getLastIndividuoFila1().getTempoChegadaFila1());

			if(servidor.getStatus()==OCUPADO && servidor.getIndividuoAtual().getTipo()==1)
			{
				estatistica.atualizaPrimeiroMometoN1(filas.sizeFila1(), filas.sizeFila1()+1);
			}
			else
			{

				estatistica.atualizaPrimeiroMometoN1(filas.sizeFila1(), filas.sizeFila1());
			}
		}
		return filas.getLastIndividuoFila1().getTempoChegadaFila1();

	}

	double tratarTerminoServico(Filas &filas, Servidor &servidor) {
		Individuo temp(servidor.getIndividuoAtual());
		servidor.setStatus(OCIOSO);
		if (temp.getTipo() == 1)
		{
			temp.setTipo(2);
			temp.setTempoChegadaFila2(temp.getTempoChegadaServidor1()+ temp.getX1());
			filas.chegadaFila2(temp);

			if(temp.getCor() == rodadaAtual)
			{
				estatistica.setTempoFimEvento1(temp.getTempoChegadaServidor1() + temp.getX1());
				estatistica.setTempoFimEvento2(temp.getTempoChegadaServidor1() + temp.getX1());
				estatistica.atualizaPrimeiroMometoN1(filas.sizeFila1(), filas.sizeFila1()+1);
				estatistica.atualizaPrimeiroMomentoN2(filas.sizeFila2(), filas.sizeFila2());

			}

			return temp.getTempoChegadaServidor1() + temp.getX1();
		}

		else
		{
			if (temp.getCor() == rodadaAtual)
			{
				quantIndividuosAtendidosRodada++;
				estatistica.armazenaEstatistica(temp);
				estatistica.setTempoFimEvento2(temp.getTempoChegadaServidor2()+temp.getXr());
				estatistica.atualizaPrimeiroMomentoN2(filas.sizeFila2(), filas.sizeFila2()+1);

				if (quantIndividuosAtendidosRodada == tamRodada)
				{
					terminaRodada(filas, servidor, temp.getTempoChegadaServidor2()+temp.getXr());
				}
			}

			return temp.getTempoChegadaServidor2()+temp.getXr();
		}
	}

	double tratarInterrupcao(Filas &filas, Servidor &servidor, double tempoAtual) {
		Individuo temp(servidor.getIndividuoAtual());

		temp.setXr(temp.getXr()	- (tempoAtual - temp.getTempoChegadaServidor2()));
		filas.retornaFila2(temp);
		servidor.setStatus(OCIOSO);
		return tratarChegadaFila1(filas, servidor);
	}

	double atenderFila2(Filas &filas, Servidor &servidor,double const &tempoAtual) {
		Individuo temp = filas.removeFirstIndividuoFila2();
		temp.setTempoChegadaServidor2(tempoAtual);
		if (temp.getX2() == 0) {
			temp.setX2(servidor.geraServico());
			temp.setXr(temp.getX2());
		}
		servidor.setStatus(OCUPADO);
		servidor.setIndividuoAtual(temp);
		return tempoAtual;
	}

	double atenderFila1(Filas &filas, Servidor &servidor,double const &tempoAtual) {
		Individuo temp = filas.removeFirstIndividuoFila1();
		temp.setTempoChegadaServidor1(tempoAtual);
		temp.setX1(servidor.geraServico());
		servidor.setStatus(OCUPADO);
		servidor.setIndividuoAtual(temp);
		return tempoAtual;
	}
};
#endif

